/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <devmon/driver_abi.h>
#include <dlfcn.h>
#include <gtest/gtest.h>
#include <test_utilities/test_base.h>

#include "../../../drivers/bus/i2c/i2c.h"
#include "../../../drivers/internal/manager.h"

using namespace dev;

namespace drivers {
namespace bus {
namespace i2c_test {

class i2c_test_service : public mc::engine::service {
public:
    i2c_test_service(const std::string& name) : mc::engine::service(name) {
    }
};

class I2cAbiTest : public mc::test::TestWithEngine {
public:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        // 动态创建服务实例，避免全局静态初始化导致的析构顺序问题
        m_test_service = mc::make_shared<i2c_test_service>("bmc.kepler.test_i2c");
        m_test_service->init();
        m_test_service->start();
        load_driver();
    }

    static void TearDownTestSuite() {
        m_test_service->stop();
        
        // 清理设备容器，避免引用已关闭的动态库
        m_devices.clear();

        // 不手动dlclose，避免静态对象析构时访问已卸载的动态库导致SIGSEGV
        // 让系统在程序退出时自动卸载动态库
        m_test_service.reset();
        TestWithEngine::TearDownTestSuite();
    }

    void SetUp() override {
    }

    void TearDown() override {
    }

    static void load_driver() {
        m_driver_handle = dlopen("./opt/bmc/drivers/libI2c.so", RTLD_LAZY);
        if (m_driver_handle == nullptr) {
            MC_THROW(mc::system_exception, "Failed to load driver: ${error}", ("error", dlerror()));
        }
        register_device_driver_func func = reinterpret_cast<register_device_driver_func>(
            dlsym(m_driver_handle, "register_device_driver"));
        MC_ASSERT_THROW(func, mc::bad_function_call_exception,
                        "Failed to get register_device_driver function: ${error}",
                        ("error", dlerror()));

        device_driver_t* devices       = nullptr;
        uint8_t          devices_count = 0;
        status_t         ret           = func(&devices, &devices_count);
        MC_ASSERT_THROW(ret == STATUS_OK, mc::bad_function_call_exception,
                        "Failed to get device driver manager: ${error}", ("error", ret));

        m_devices.clear();
        m_devices.reserve(devices_count);
        for (uint8_t i = 0; i < devices_count; i++) {
            auto device_driver = std::make_shared<device_driver_t>(devices[i]);
            m_devices.emplace(device_driver->device_name, device_driver);
        }
    }

    mc::dict create_test_connector(uint8_t system_id, uint8_t position, uint8_t slot) {
        return mc::dict{{"SystemId", system_id}, {"Position", position}, {"Slot", slot}};
    }

    mc::dict create_test_csr_object(const std::string& object_name, uint8_t id, uint32_t speed,
                                    uint8_t mode, uint8_t slave_addr, bool use_smbus) {
        return mc::dict{{"object_name", object_name},
                        {"Id", id},
                        {"Speed", speed},
                        {"Mode", mode},
                        {"SlaveAddr", slave_addr},
                        {"UseSmbus", use_smbus}};
    }

    // 创建内部I2C对象
    void create_internal_i2c_object(const std::string& object_name, uint8_t id, uint32_t speed,
                                    uint8_t mode, uint8_t slave_addr, bool use_smbus) {
        auto&            manager = dev::device_manager::get_instance();
        mc::mutable_dict csr_data;
        csr_data["Id"]        = id;
        csr_data["Speed"]     = speed;
        csr_data["Mode"]      = mode;
        csr_data["SlaveAddr"] = slave_addr;
        csr_data["UseSmbus"]  = use_smbus;

        auto bus_ptr = manager.create_bus(object_name, "I2c", csr_data);
        ASSERT_TRUE(bus_ptr != nullptr);
    }

    static mc::shared_ptr<i2c_test_service>                                  m_test_service;
    static std::unordered_map<std::string, std::shared_ptr<device_driver_t>> m_devices;
    static void*                                                             m_driver_handle;
};

// 静态成员变量定义 - 空初始化，在SetUpTestSuite中动态创建
mc::shared_ptr<i2c_test_service> I2cAbiTest::m_test_service;
std::unordered_map<std::string, std::shared_ptr<device_driver_t>> I2cAbiTest::m_devices;
void* I2cAbiTest::m_driver_handle = nullptr;

// ========================= 驱动注册功能测试 =========================

TEST_F(I2cAbiTest, register_device_driver_success) {
    // 验证驱动注册成功，并且包含预期的设备类型
    EXPECT_EQ(m_devices.size(), 1);
    EXPECT_TRUE(m_devices.find("I2c") != m_devices.end());
}

TEST_F(I2cAbiTest, device_driver_structure_validation) {
    // 验证设备驱动的结构完整性
    for (const auto& [device_name, device_driver] : m_devices) {
        EXPECT_FALSE(std::string(device_driver->device_name).empty());
        EXPECT_TRUE(device_driver->ctor != nullptr);
        EXPECT_TRUE(device_driver->init != nullptr);
        EXPECT_TRUE(device_driver->start != nullptr);
        EXPECT_TRUE(device_driver->stop != nullptr);
    }
}

// ========================= I2C设备创建测试 =========================

TEST_F(I2cAbiTest, create_i2c_success) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_device");
    ASSERT_TRUE(device != nullptr);
}

TEST_F(I2cAbiTest, create_i2c_null_service) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    // 传入空服务指针应该返回nullptr
    auto device = device_driver->ctor(nullptr, "test_i2c_device");
    EXPECT_EQ(device, nullptr);
}

TEST_F(I2cAbiTest, create_i2c_null_name) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    // 传入空名称应该返回nullptr
    auto device = device_driver->ctor(m_test_service.get(), nullptr);
    EXPECT_EQ(device, nullptr);
}

// ========================= I2C设备初始化测试 =========================

TEST_F(I2cAbiTest, init_i2c_success) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_init");
    ASSERT_TRUE(device != nullptr);

    // 先创建内部I2C对象
    std::string object_name = "test_i2c_internal";
    create_internal_i2c_object(object_name, 0, 100000, 0, 0x50, false);

    // 创建测试配置
    auto csr_object = create_test_csr_object(object_name, 0, 100000, 0, 0x50, false);
    auto connector  = create_test_connector(1, 1, 1);

    status_t ret = device_driver->init(device, &csr_object, &connector);
    EXPECT_EQ(ret, STATUS_OK);
}

TEST_F(I2cAbiTest, init_i2c_without_internal_object) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_no_internal");
    ASSERT_TRUE(device != nullptr);

    // 创建测试配置，但不创建内部对象
    auto csr_object = create_test_csr_object("non_existent_i2c", 0, 100000, 0, 0x50, false);
    auto connector  = create_test_connector(1, 1, 1);

    // 应该返回STATUS_ERROR，因为内部对象不存在
    status_t ret = device_driver->init(device, &csr_object, &connector);
    EXPECT_EQ(ret, STATUS_ERROR);
}

TEST_F(I2cAbiTest, init_i2c_null_params) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_null_init");
    ASSERT_TRUE(device != nullptr);

    // 测试空参数初始化
    status_t ret = device_driver->init(device, nullptr, nullptr);
    EXPECT_EQ(ret, STATUS_ERROR);
}

TEST_F(I2cAbiTest, init_i2c_null_device) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    auto csr_object = create_test_csr_object("test_i2c_null_device", 0, 100000, 0, 0x50, false);
    auto connector  = create_test_connector(1, 1, 1);

    // 测试空设备指针
    status_t ret = device_driver->init(nullptr, &csr_object, &connector);
    EXPECT_EQ(ret, STATUS_ERROR);
}

// ========================= 多设备测试 =========================

TEST_F(I2cAbiTest, multiple_i2c_devices_creation) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    // 创建多个I2C设备
    std::vector<void*> devices;
    for (int i = 0; i < 3; i++) {
        std::string device_name = "test_i2c_device_" + std::to_string(i);
        auto        device      = device_driver->ctor(m_test_service.get(), device_name.c_str());
        ASSERT_TRUE(device != nullptr);
        devices.push_back(device);
    }

    // 验证所有设备都是不同的实例
    for (size_t i = 0; i < devices.size(); i++) {
        for (size_t j = i + 1; j < devices.size(); j++) {
            EXPECT_NE(devices[i], devices[j]);
        }
    }
}

// ========================= 完整生命周期测试 =========================

TEST_F(I2cAbiTest, i2c_full_lifecycle) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    // 1. 创建设备
    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_lifecycle");
    ASSERT_TRUE(device != nullptr);

    // 2. 创建内部I2C对象
    std::string object_name = "test_i2c_lifecycle_internal";
    create_internal_i2c_object(object_name, 0, 100000, 0, 0x50, false);

    // 3. 初始化设备
    auto     csr_object = create_test_csr_object(object_name, 0, 100000, 0, 0x50, false);
    auto     connector  = create_test_connector(1, 1, 1);
    status_t init_ret   = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    // 4. 执行读写操作
    dev::I2c_object* i2c_device = static_cast<dev::I2c_object*>(device);

    // 执行写入操作
    std::string          test_data = "test_data";
    std::vector<uint8_t> test_data_vec(test_data.begin(), test_data.end());
    ACCESS_DATA_S        write_input = {.addr_width     = 1,
                                        .offset_width   = 1,
                                        .mask           = 0,
                                        .addr           = 0x50,
                                        .offset         = 0x00,
                                        .length         = static_cast<uint32_t>(test_data.length()),
                                        .in_buffer      = test_data_vec,
                                        .out_buffer     = std::vector<uint8_t>(),
                                        .read_time_out  = 100,
                                        .write_time_out = 100,
                                        .optype         = 1};

    uint32_t write_result = i2c_device->m_interface_i2c.m_bus_i2c->write(write_input);
    EXPECT_EQ(write_result, 0);

    // 执行读取操作
    ACCESS_DATA_S read_input = {.addr_width     = 1,
                                .offset_width   = 1,
                                .mask           = 0,
                                .addr           = 0x50,
                                .offset         = 0x00,
                                .length         = 4,
                                .in_buffer      = std::vector<uint8_t>(),
                                .out_buffer     = std::vector<uint8_t>(),
                                .read_time_out  = 100,
                                .write_time_out = 100,
                                .optype         = 0};

    uint32_t read_result = i2c_device->m_interface_i2c.m_bus_i2c->read(read_input);
    EXPECT_EQ(read_result, 0);

    // 5. 设备可以正常使用，生命周期完整
    EXPECT_TRUE(device != nullptr);
}

// ========================= I2C属性验证测试 =========================

TEST_F(I2cAbiTest, i2c_properties_validation) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);

    // 创建I2C设备
    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_properties");
    ASSERT_TRUE(device != nullptr);

    // 设置测试参数
    std::string object_name     = "test_i2c_properties_internal";
    uint8_t     test_id         = 2;
    uint32_t    test_speed      = 3400; // 3400kbps
    uint8_t     test_mode       = 1;
    uint8_t     test_slave_addr = 0x52;
    bool        test_use_smbus  = true;

    // 创建内部I2C对象
    create_internal_i2c_object(object_name, test_id, test_speed, test_mode, test_slave_addr,
                               test_use_smbus);

    // 创建配置对象
    auto csr_object = create_test_csr_object(object_name, test_id, test_speed, test_mode,
                                             test_slave_addr, test_use_smbus);
    auto connector  = create_test_connector(1, 1, 1);

    // 初始化设备
    status_t init_ret = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    // 获取I2C对象指针
    dev::I2c_object* i2c_device = reinterpret_cast<dev::I2c_object*>(device);
    ASSERT_TRUE(i2c_device != nullptr);

    // 验证属性值 - 现在在m_interface_i2c中
    EXPECT_EQ(i2c_device->m_interface_i2c.Id, test_id);
    EXPECT_EQ(i2c_device->m_interface_i2c.Speed, test_speed);
    EXPECT_EQ(i2c_device->m_interface_i2c.Mode, test_mode);
    EXPECT_EQ(i2c_device->m_interface_i2c.SlaveAddr, test_slave_addr);
    EXPECT_EQ(i2c_device->m_interface_i2c.UseSmbus, test_use_smbus);
}

// ========================= 底层驱动功能测试 =========================
TEST_F(I2cAbiTest, i2c_driver_memory_operations) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);
    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_memory");
    ASSERT_TRUE(device != nullptr);

    // 创建内部I2C对象
    std::string object_name = "test_i2c_memory_internal";
    create_internal_i2c_object(object_name, 0, 100000, 0, 0x50, false);

    auto     csr_object = create_test_csr_object(object_name, 0, 100000, 0, 0x50, false);
    auto     connector  = create_test_connector(1, 1, 1);
    status_t init_ret   = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    dev::I2c_object* i2c_device = static_cast<dev::I2c_object*>(device);

    // 设置底层驱动的offset_width
    i2c_device->m_interface_i2c.m_bus_i2c->m_i2c_drv->set_offset_width(2);

    // 测试写入和读取操作
    std::string          test_data = "\x01\x02\x03\x04";
    std::vector<uint8_t> test_data_vec(test_data.begin(), test_data.end());
    ACCESS_DATA_S        write_data = {};
    write_data.addr                 = 0x50;
    write_data.offset               = 0x10;
    write_data.offset_width         = 2;
    write_data.length               = static_cast<uint32_t>(test_data.length());
    write_data.in_buffer            = test_data_vec;

    uint32_t write_ret = i2c_device->m_interface_i2c.m_bus_i2c->write(write_data);
    EXPECT_EQ(write_ret, 0);

    ACCESS_DATA_S read_data = {};
    read_data.addr          = 0x50;
    read_data.offset        = 0x10;
    read_data.offset_width  = 2;
    read_data.length        = static_cast<uint32_t>(test_data.length());

    uint32_t read_ret = i2c_device->m_interface_i2c.m_bus_i2c->read(read_data);
    EXPECT_EQ(read_ret, 0);
    std::string read_result(read_data.out_buffer.begin(), read_data.out_buffer.end());
    EXPECT_EQ(read_result, test_data);
}

TEST_F(I2cAbiTest, i2c_driver_parameter_validation) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);
    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_validation");
    ASSERT_TRUE(device != nullptr);

    // 创建内部I2C对象
    std::string object_name = "test_i2c_validation_internal";
    create_internal_i2c_object(object_name, 0, 100000, 0, 0x50, false);

    auto     csr_object = create_test_csr_object(object_name, 0, 100000, 0, 0x50, false);
    auto     connector  = create_test_connector(1, 1, 1);
    status_t init_ret   = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    dev::I2c_object* i2c_device = reinterpret_cast<dev::I2c_object*>(device);

    // 测试偏移量宽度验证
    std::string          test_invalid_data = "test";
    std::vector<uint8_t> test_invalid_data_vec(test_invalid_data.begin(), test_invalid_data.end());
    ACCESS_DATA_S        invalid_offset_data = {};
    invalid_offset_data.addr                 = 0x50;
    invalid_offset_data.offset               = 0x10;
    invalid_offset_data.offset_width         = 5; // 超过最大值4
    invalid_offset_data.length               = 4;
    invalid_offset_data.in_buffer            = test_invalid_data_vec;

    EXPECT_THROW(i2c_device->m_interface_i2c.m_bus_i2c->write(invalid_offset_data),
                 mc::invalid_arg_exception);
    EXPECT_THROW(i2c_device->m_interface_i2c.m_bus_i2c->read(invalid_offset_data),
                 mc::invalid_arg_exception);
}

TEST_F(I2cAbiTest, i2c_driver_bus_operations) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);
    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_bus");
    ASSERT_TRUE(device != nullptr);

    // 创建内部I2C对象
    std::string object_name = "test_i2c_bus_internal";
    create_internal_i2c_object(object_name, 0, 100000, 0, 0x50, false);

    auto     csr_object = create_test_csr_object(object_name, 0, 100000, 0, 0x50, false);
    auto     connector  = create_test_connector(1, 1, 1);
    status_t init_ret   = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    dev::I2c_object* i2c_device = static_cast<dev::I2c_object*>(device);

    // 测试总线锁定和解锁操作
    EXPECT_NO_THROW(i2c_device->m_interface_i2c.m_bus_i2c->bus_lock());
    EXPECT_NO_THROW(i2c_device->m_interface_i2c.m_bus_i2c->bus_unlock());

    // 测试获取ID
    EXPECT_EQ(i2c_device->m_interface_i2c.m_bus_i2c->get_id(), 0);
}

TEST_F(I2cAbiTest, i2c_driver_different_offset_widths) {
    auto device_driver = m_devices["I2c"];
    ASSERT_TRUE(device_driver != nullptr);
    auto device = device_driver->ctor(m_test_service.get(), "test_i2c_offset_widths");
    ASSERT_TRUE(device != nullptr);

    // 创建内部I2C对象
    std::string object_name = "test_i2c_offset_widths_internal";
    create_internal_i2c_object(object_name, 0, 100000, 0, 0x50, false);

    auto     csr_object = create_test_csr_object(object_name, 0, 100000, 0, 0x50, false);
    auto     connector  = create_test_connector(1, 1, 1);
    status_t init_ret   = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    dev::I2c_object* i2c_device = static_cast<dev::I2c_object*>(device);

    // 测试不同的偏移量宽度
    std::vector<uint8_t>  offset_widths = {1, 2, 3, 4};
    std::vector<uint32_t> offsets       = {0x01, 0x0102, 0x010203, 0x01020304};

    for (size_t i = 0; i < offset_widths.size(); i++) {
        uint8_t     offset_width = offset_widths[i];
        uint32_t    offset       = offsets[i];
        std::string test_data    = "\x11\x22\x33\x44";

        // 设置底层驱动的offset_width
        i2c_device->m_interface_i2c.m_bus_i2c->m_i2c_drv->set_offset_width(offset_width);

        // 写入数据
        std::vector<uint8_t> test_data_vec(test_data.begin(), test_data.end());
        ACCESS_DATA_S        write_data = {};
        write_data.addr                 = 0x50;
        write_data.offset               = offset;
        write_data.offset_width         = offset_width;
        write_data.length               = static_cast<uint32_t>(test_data.length());
        write_data.in_buffer            = test_data_vec;

        EXPECT_NO_THROW(i2c_device->m_interface_i2c.m_bus_i2c->write(write_data));

        // 读取数据验证
        ACCESS_DATA_S read_data = {};
        read_data.addr          = 0x50;
        read_data.offset        = offset;
        read_data.offset_width  = offset_width;
        read_data.length        = static_cast<uint32_t>(test_data.length());

        uint32_t read_ret = i2c_device->m_interface_i2c.m_bus_i2c->read(read_data);
        EXPECT_EQ(read_ret, 0);
        std::string read_result(read_data.out_buffer.begin(), read_data.out_buffer.end());
        EXPECT_EQ(read_result, test_data);
    }
}

} // namespace i2c_test
} // namespace bus
} // namespace drivers